package com.itcast.demo.datamask.interceptor;

import com.itcast.demo.datamask.annotation.Desensitization;
import com.itcast.demo.datamask.enumpackage.StrategyEnum;
import org.apache.ibatis.executor.resultset.ResultSetHandler;
import org.apache.ibatis.plugin.Interceptor;
import org.apache.ibatis.plugin.Intercepts;
import org.apache.ibatis.plugin.Invocation;
import org.apache.ibatis.plugin.Signature;
import org.apache.ibatis.reflection.MetaObject;
import org.apache.ibatis.reflection.SystemMetaObject;
import org.springframework.stereotype.Component;

import java.lang.reflect.Field;
import java.sql.Statement;
import java.util.List;
import java.util.Properties;
import java.util.stream.Stream;

@Component
@Intercepts(@Signature(type = ResultSetHandler.class, method = "handleResultSets", args = {Statement.class}))
public class DesensitizationPlugin implements Interceptor {
    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        // 获取结果集
        List<Object> records = (List<Object>) invocation.proceed();
        // 处理结果集
        records.forEach(this::desensitization);
        return records;
    }

    /**
     * 判断哪些需要脱敏处理
     *
     * @param source 脱敏之前的源对象
     * @return
     */
    private void desensitization(Object source) {
        // 反射获取类型中的所有属性，判断那个需要进行脱敏
        Class<?> sourceClass = source.getClass();
        MetaObject metaObject = SystemMetaObject.forObject(source);
        Stream.of(sourceClass.getDeclaredFields())
                .filter(field -> field.isAnnotationPresent(Desensitization.class))
                .forEach(field -> doDesensitization(metaObject, field));
    }

    /**
     * 2*真正的脱敏处理
     * 3*@parammetaObject
     * 4
     */
    private void doDesensitization(MetaObject metaObject, Field field) {
        String name = field.getName();
        Object value = metaObject.getValue(name);
        if (value != null && metaObject.getGetterType(name) == String.class) {
            Desensitization annotation = field.getAnnotation(Desensitization.class);
            StrategyEnum strategy = annotation.strategy();
            String apply = strategy.getDesensitizer().apply((String) value);
            metaObject.setValue(name, apply);
        }
    }

    @Override
    public Object plugin(Object target) {
        return Interceptor.super.plugin(target);
    }

    @Override
    public void setProperties(Properties properties) {
        Interceptor.super.setProperties(properties);
    }
}
